package util;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESedeKeySpec;
import java.io.Serializable;
import java.nio.charset.StandardCharsets;

/**
 * @author pengjz
 * @date 2019/10/23 10:51
 */
public class TripleDesUtil implements Serializable {

    private static final String EMPTY_STR = "";

    private static final int KEY_LEN = 24;

    private static final BASE64Encoder ENCODER = new BASE64Encoder();

    private static final BASE64Decoder DECODER = new BASE64Decoder();

    /**
     * 定义加密算法，有DES、DESede(3DES)
     */
    private static final String KEY_ALGORITHM = "DESede";

    /**
     * 算法名称/加密模式/填充方式
     */
    private static final String CIPHER_ALGORITHM = "DESede/ECB/PKCS5Padding";

    public static String tripleDesEncrypt(String src, String key) {
        if (key == null || src == null) {
            return EMPTY_STR;
        }
        try {
            DESedeKeySpec keySpec = new DESedeKeySpec(buildKey(key));
            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(KEY_ALGORITHM);
            SecretKey secretKey = keyFactory.generateSecret(keySpec);
            // 获取密码实例
            Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
            cipher.init(Cipher.ENCRYPT_MODE, secretKey);
            byte[] b = cipher.doFinal(src.getBytes());
            // 执行加密并返回Base64字符串
            return ENCODER.encode(b);
        } catch (Exception e) {
            e.printStackTrace();
            return EMPTY_STR;
        }
    }

    public static String tripleDesDecrypt(String src, String key) {
        if (key == null || src == null) {
            return EMPTY_STR;
        }
        try {
            DESedeKeySpec keySpec = new DESedeKeySpec(buildKey(key));
            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(KEY_ALGORITHM);
            SecretKey secretKey = keyFactory.generateSecret(keySpec);
            // 获取密码实例
            Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
            cipher.init(Cipher.DECRYPT_MODE, secretKey);
            byte[] b = cipher.doFinal(DECODER.decodeBuffer(src));
            return new String(b, StandardCharsets.UTF_8);
        } catch (Exception e) {
            e.printStackTrace();
            return EMPTY_STR;
        }
    }
    public static String tripleDesDecrypt(byte[] src, String key) {
        if (key == null || src == null) {
            return EMPTY_STR;
        }
        try {
            DESedeKeySpec keySpec = new DESedeKeySpec(buildKey(key));
            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(KEY_ALGORITHM);
            SecretKey secretKey = keyFactory.generateSecret(keySpec);
            // 获取密码实例
            Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
            cipher.init(Cipher.DECRYPT_MODE, secretKey);
            byte[] b = cipher.doFinal(src);
            return new String(b, StandardCharsets.UTF_8);
        } catch (Exception e) {
            e.printStackTrace();
            return EMPTY_STR;
        }
    }

    /**
     * 根据字符串生成密钥字节数组
     *
     * @param keyStr 密钥字符串
     * @return 长度密钥字节数组
     */
    private static byte[] buildKey(String keyStr) {
        //声明一个24位的字节数组，默认里面都是0
        byte[] key = new byte[KEY_LEN];
        //将字符串转成字节数组
        byte[] temp = keyStr.getBytes(StandardCharsets.UTF_8);
        ///执行数组拷贝
        if (key.length > temp.length) {
            //如果temp不够24位，则拷贝temp数组整个长度的内容到key数组中
            System.arraycopy(temp, 0, key, 0, temp.length);
        } else {
            //如果temp大于24位，则拷贝temp数组24个长度的内容到key数组中
            System.arraycopy(temp, 0, key, 0, key.length);
        }
        return key;
    }

    public static void main(String[] args) {
//        String in = tripleDesEncrypt("201909291549398508", "beantechs+1d13ef12d11a44b6aa44823e1478b529");
//        System.out.println("in:" + in + "|");
        String out = tripleDesDecrypt("/YySyh7tAehC4VVhqIXn1w==", "beantechs");
//        System.out.println("out:" + out);
    }

}
